
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                               proc.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include "type.h"
#include "const.h"
#include "protect.h"
//#include "proto.h"
#include "string.h"
#include "proc.h"
#include "proto.h"
#include "global.h"

/*======================================================================*
                              schedule
 *======================================================================*/
PUBLIC void schedule()
{
	/*PROCESS* p;
	int	 greatest_ticks = 0;

	while (!greatest_ticks) {
		for (p = proc_table; p < proc_table+NR_TASKS; p++) {
			if(p->sleep_ticks == 0){//如果进程睡眠时间大于0,就不会将时间分配给进程
				if (p->ticks > greatest_ticks) {
					greatest_ticks = p->ticks;
					p_proc_ready = p;
				}
			}
		}

		if (!greatest_ticks) {
			for (p = proc_table; p < proc_table+NR_TASKS; p++) {
				p->ticks = p->total_ticks;
			}
		}
	}
	//disp_int(greatest_ticks);*/
	
	//轮流调度所有进程，如果该进程处于睡眠状态，就不考虑
	//找到当前进程对应的序号
	int i=0;
	while(i<NR_TASKS){
		if(proc_table+i == p_proc_ready){
			break;
		}
		i++;
	}
	int cur_proc_num=i;
	//disp_str("cur_proc: ");disp_int(i);
	
	//调用该进程后面的进程，如果处于睡眠状态，就下一个
	i++;
	if(i==NR_TASKS){
		i=0;
	}
	PROCESS* p=proc_table+i;
	while(i != cur_proc_num){
		if(p->sleep_ticks == 0){
			p_proc_ready=p;
			break;
		}
		
		i++;
		if(i == NR_TASKS){
			i=0;
		}
		p=proc_table+i;
	}
	
	//disp_str("proc ready: ");disp_int(i);

	//如果其他进程都处于睡眠状态 且 当前进程剩余时间为0,这不太可能……
	if((i == cur_proc_num) && (p_proc_ready->ticks == 0)){
		disp_str("??");
	}
}

/*======================================================================*
                           sys_get_ticks
 *======================================================================*/
PUBLIC int sys_get_ticks()
{
	return ticks;
}

/*======================================================================*
                           sys_print_str
 *======================================================================*/
PUBLIC void sys_print_str(char* str)
{
	//disp_str(global_str);
	disp_str(str);
}

/*======================================================================*
                           sys_sleep
 *======================================================================*/
PUBLIC void sys_sleep(int milli_seconds)
{
	p_proc_ready->sleep_ticks=milli_seconds*HZ/1000;//设置睡眠时间
	//disp_int(p_proc_ready->sleep_ticks);
	
	schedule();
	p_proc_ready->ticks++;
	//milli_delay(10);//先将这次的时间片用光

	//disp_str(" * ");
	//disp_int(milli_seconds);
}

/*======================================================================*
                           sys_time_delay
 *======================================================================*/
PUBLIC void sys_time_delay(int milli_sec)
{
        int t = get_ticks();
		//disp_str(" & ");
        while(((get_ticks() - t) * 1000 / HZ) < milli_sec) {}
}

/*======================================================================*
                           sys_p_sema
 *======================================================================*/
PUBLIC void sys_p_sema(SEMAPHORE* sema)
{
	sema->s_num--;

	if(sema->s_num < 0){
		//disp_str(" sleep a proc: ");disp_str(p_proc_ready->p_name);
		
		sema->p_procs[sema->p_procs_len]=p_proc_ready;//将当前进程加入等待队列
		sema->p_procs_len++;
		sleep((work_time_unit*1000/HZ)*100);//令该进程睡眠100个工作时间
	}
}

/*======================================================================*
                           sys_v_sema
 *======================================================================*/
PUBLIC void sys_v_sema(SEMAPHORE* sema)
{
	sema->s_num++;
	if(sema->s_num <= 0){//如果有等待进程，唤醒第一个进程
		PROCESS* p_proc = sema->p_procs[0];
		p_proc->sleep_ticks=0;
		//p_proc_ready=p_proc;//好像不需要这一句，因为时间结束后clock_handle会自动调用schedule
		
		//将信号量里的等待队列全部前移一位
		int i=1;
		while(i < sema->p_procs_len){
			sema->p_procs[i-1]=sema->p_procs[i];
			i++;
		}
		sema->p_procs_len--;
		
		//disp_str(" wake a proc: ");disp_str(p_proc->p_name);
		//milli_delay(10);//消耗完当前的时间片
	}
}
